/*
 * hdf5_parser_read.hpp
 *
 *  Created on: Aug 5, 2013
 *      Author: paste
 */

#ifndef HDF5_PARSER_READ_HPP_
#define HDF5_PARSER_READ_HPP_

#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <vector>
#include <string>
#include <map>
#include "H5Cpp.h"

namespace boost {
namespace property_tree {
namespace hdf5_parser {

typedef std::pair<boost::shared_ptr<H5::H5File>, boost::shared_ptr<H5::CommonFG> > FileGroupPair;

int read_itr(hid_t group, const char *name, void *data)
{
  FileGroupPair *fileGroupPair = reinterpret_cast<FileGroupPair *>(data);
  boost::shared_ptr<H5::CommonFG> containerPtr = fileGroupPair->second;
  boost::shared_ptr<H5::H5File> filePtr = fileGroupPair->first;
  H5G_stat_t statbuf;
  containerPtr->getObjinfo(name, statbuf);

  // If this is a group, iterate through it
  if (statbuf.type == H5G_GROUP) {
    int index = 0;
    boost::shared_ptr<H5::CommonFG> grpPtr(
        new H5::Group(containerPtr->openGroup(name)));
    FileGroupPair nextFGPair(filePtr, grpPtr);
    containerPtr->iterateElems(name, &index, &read_itr,
        static_cast<void *>(&nextFGPair));
  }

  // If this is a dataset, check for a matlab dataset
  else if (statbuf.type == H5G_DATASET) {
    H5::DataSet ds = containerPtr->openDataSet(name);
    H5::DataType dt = ds.getDataType();
    // Everything in a matlab file is either an integer type or a float type
    H5T_class_t cls = dt.getClass();
    std::cout << "name:  " << name << std::endl;
    std::cout << "class: " << cls << std::endl;
    if (cls == H5T_INTEGER || cls == H5T_FLOAT) {
      // Get the MATLAB type (as an attribute)
      try {
        H5::Attribute matlabClassAttr = ds.openAttribute("MATLAB_class");
        H5::DataType attrDataType = matlabClassAttr.getDataType();
        std::string matlabClassStr;
        matlabClassAttr.read(attrDataType, matlabClassStr);

        std::cout << matlabClassStr << std::endl;
      } catch (const H5::AttributeIException &e) {
        std::cout << "(no matlab type?)" << std::endl;
      }
    }
  }
  return 0;
}

template<class Ptree>
void read_hdf5_internal(
    std::basic_istream<typename Ptree::key_type::value_type> &stream, Ptree &pt,
    const std::string &filename)
{

  typedef typename Ptree::key_type::value_type Ch;
  typedef typename std::vector<Ch>::iterator It;

  try {
    // Do not report errors to the console
    H5::Exception::dontPrint();

    // Open the file read-only
    boost::shared_ptr<H5::H5File> file(
        new H5::H5File(filename.c_str(), H5F_ACC_RDONLY));

    // The starting index (should be zero?)
    int index = 0;

    // Iterate over all objects in the file
    FileGroupPair fileGroupPair(file, file);
    file->iterateElems("/", &index, &read_itr,
        static_cast<void *>(&fileGroupPair));

    // catch failure caused by the H5File operations
  } catch (const H5::FileIException &error) {
    error.printError();
  }

// catch failure caused by the DataSet operations
  catch (const H5::DataSetIException &error) {
    error.printError();
  }

// catch failure caused by the DataSpace operations
  catch (const H5::DataSpaceIException &error) {
    error.printError();
  }

// catch failure caused by the DataSpace operations
  catch (const H5::DataTypeIException &error) {
    error.printError();
  }

//  // Load data into vector
//  std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
//      std::istreambuf_iterator<Ch>());
//  if (!stream.good())
//    BOOST_PROPERTY_TREE_THROW(json_parser_error("read error", filename, 0));
//
//  // Prepare grammar
//  json_grammar<Ptree> g;
//
//  // Parse
//  try {
//    parse_info<It> pi = parse(v.begin(), v.end(), g,
//        space_p | comment_p("//") | comment_p("/*", "*/"));
//    if (!pi.hit || !pi.full)
//      BOOST_PROPERTY_TREE_THROW(
//          (parser_error<std::string, It>(v.begin(), "syntax error")));
//  } catch (parser_error<std::string, It> &e) {
//    BOOST_PROPERTY_TREE_THROW(
//        json_parser_error(e.descriptor, filename,
//            count_lines<It, Ch>(v.begin(), e.where)));
//  }
//
//  // Swap grammar context root and pt
//  pt.swap(g.c.root);

}

} /* namespace hdf5_parser */
} /* namespace property_tree */
} /* namespace boost */

#endif /* HDF5_PARSER_READ_HPP_ */
